home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / drdobbs / 1991 / 02 / nelson / churnx.c < prev    next >
C/C++ Source or Header  |  1990-05-24  |  6KB  |  200 lines

  1. /*
  2.  * Listing 15 -- churnx.c
  3.  *
  4.  * This is a utility program used to test compression/decompression
  5.  * programs for accuracy, speed, and compression ratios.  Calling
  6.  * CHURN.EXE with a single argument will cause CHURN to compress then
  7.  * decompress every file in the specified directory tree, checking the
  8.  * compression ratio and the accuracy of the operation.  This is a good
  9.  * program to run overnight when you think your new algorithm works
  10.  * properly.
  11.  *
  12.  * This program will presently compile on my SCO Xenix system.
  13.  * I don't know if the directory access and time routines are portable
  14.  * to other *NIX systems.
  15.  *
  16.  * To build this program:
  17.  *
  18.  *   cc -o churnx churnx.c -lx
  19.  *
  20.  *
  21.  */
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <time.h>
  26. #include <sys/ndir.h>
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29.  
  30. /*
  31.  * Some global variables.
  32.  */
  33. long total_input_bytes;
  34. long total_output_bytes;
  35.  
  36. /*
  37.  * Declarations for global routines.
  38.  */
  39. void churn_files( char *path );
  40. void close_all_the_files( void );
  41. int compress( char *file_name );
  42.  
  43. /*
  44.  * main() doesn't have to do a whole lot in this program.  It
  45.  * reads in the command line to determine what the root directory
  46.  * to start looking at is, then it initializes the total byte counts
  47.  * and the start time.  It can then call churn_files(), which does all
  48.  * the work, then report on the statistics resulting from churn_files.
  49.  */
  50. void main( int argc, char *argv[] )
  51. {
  52.     long int start_time;
  53.     long int stop_time;
  54.     char argument[ 81 ];
  55.  
  56.     if ( argc < 2 )
  57.         strcpy( argument, "/" );
  58.     else
  59.         strcpy( argument, argv[ 1 ] );
  60.     total_input_bytes = 0L;
  61.     total_output_bytes = 0L;
  62.     start_time = time( (long *) 0 );
  63.     churn_files( argument );
  64.     stop_time = time( (long *) 0 );
  65.     printf( "%ld seconds elapsed time\n", stop_time - start_time );
  66.     printf( "Total input bytes: %8ld: \n", total_input_bytes );
  67.     printf( "Total output bytes: %8ld: \n", total_output_bytes );
  68.     printf( "Reduction:%ld%%  ",
  69.             100L - ( ( 100L * total_output_bytes) / total_input_bytes ) );
  70.     printf( "Bits per byte: %f\n",
  71.             8.0 * total_output_bytes / total_input_bytes );
  72.  
  73. }
  74.  
  75. /*
  76.  * churn_files() is a routine that sits in a loop looking at
  77.  * files in the directory specified by its single argument, "path".
  78.  * As each file is looked at, one of three things happens.  If it
  79.  * is a normal file, and has a compressed extension name, like ".ZIP",
  80.  * the file is ignored.  If it is a normal file, and doesn't have a
  81.  * compressed extension name, it is compressed and decompressed by
  82.  * another routine.  Finally, if the file is a subdirectory,
  83.  * churn_files() is called recursively with the file name as its
  84.  * path argument.  This is one of those rare routines where recursion
  85.  * provides a way to truly simplify the task at hand.
  86.  */
  87. void churn_files( char *path )
  88. {
  89.     DIR *dirp;
  90.     struct direct *entry;
  91.     struct stat buf;
  92.     char full_name[ 81 ];
  93.  
  94.  
  95.     dirp = opendir( path );
  96.     if ( dirp == NULL )
  97.     {
  98.     printf( "Error opening directory %s\n", path );
  99.     exit( -1 );
  100.     }
  101.     for ( entry=readdir(dirp) ; entry != NULL ; entry=readdir(dirp) )
  102.     {
  103.     if ( entry->d_name[0] != '.' )
  104.     {
  105.         strcpy( full_name, path );
  106.         strcat( full_name, "/" );
  107.         strcat( full_name, entry->d_name );
  108.         if ( stat( full_name, &buf ) == -1 )
  109.         {
  110.         printf( "Error reading stat from file %s!\n", full_name );
  111.         exit( -1 );
  112.         }
  113.         if ( buf.st_mode & 040000 )
  114.         churn_files( full_name );
  115.         else
  116.         {
  117.                 fprintf( stderr, "Testing %s\n", full_name );
  118.                 if ( !compress( full_name ) )
  119.                     fprintf( stderr, "Comparison failed!\n" );
  120.         }
  121.     }
  122.     }
  123. }
  124.  
  125. /*
  126.  * This is the routine that does the majority of the work for
  127.  * this program.  It takes a file whose name is passed here.  It then
  128.  * compresses, then decompresses that file.  It then compares the file
  129.  * to the decompressed output, and reports on the results.
  130.  */
  131. FILE *input;
  132. FILE *output;
  133. FILE *compressed;
  134.  
  135. int compress( char *file_name )
  136. {
  137.     long new_size;
  138.     long old_size;
  139.     char command_line[132];
  140.     int c;
  141.  
  142.     fflush( stdout );
  143.     printf( "%s\n", file_name );
  144.     sprintf( command_line, "./comp-1 -f %s\n", file_name );
  145.     system( command_line );
  146.     sprintf( command_line, "./expand-1\n" );
  147.     system( command_line );
  148.     input = fopen( file_name, "rb" );
  149.     output = fopen( "test.out", "rb" );
  150.     compressed = fopen( "test.cmp", "rb" );
  151.  
  152.     if ( input == NULL || output == NULL || compressed == NULL )
  153.     {
  154.         close_all_the_files();
  155.         printf( "Failed, couldn't open file!\n" );
  156.         return( 0 );
  157.     }
  158.  
  159.     fseek( input, 0L, 2 );
  160.     old_size = ftell( input );
  161.     fseek( input, 0L, 0 );
  162.     fseek( compressed, 0L, 2 );
  163.     new_size = ftell( compressed );
  164.  
  165.     printf( "Old size: %8ld: ", old_size );
  166.     printf( "New size: %8ld\n", new_size );
  167.     if ( old_size == 0L )
  168.         old_size = 1L;
  169.     printf( "Reduction: %ld%%  ",
  170.             100L - ( ( 100L * new_size ) / old_size ) );
  171.     printf( "Bits per byte: %f\n", 8.0 * new_size / old_size );
  172.     total_input_bytes += old_size;
  173.     total_output_bytes += new_size;
  174.     do
  175.     {
  176.         c = getc( input );
  177.         if ( getc( output ) != c )
  178.         {
  179.             printf( "Failed comparison!\n" );
  180.             close_all_the_files();
  181.             return( 0 );
  182.         }
  183.     }
  184.     while ( c != EOF );
  185.     printf( "File compare passed.\n" );
  186.     close_all_the_files();
  187.     return( 1 );
  188. }
  189.  
  190. void close_all_the_files()
  191. {
  192.     if ( input != NULL )
  193.         fclose( input );
  194.     if ( output != NULL )
  195.         fclose( output );
  196.     if ( compressed != NULL )
  197.         fclose( compressed );
  198. }
  199.  
  200.